package org.balabala.video.controller;

import com.alibaba.fastjson.JSON;
import org.balabala.os.client.MinIOClient;
import org.balabala.os.conf.ObjectStorageConf;
import org.balabala.os.exception.ClientNotInitException;
import org.balabala.os.management.MinIOClientManager;
import org.balabala.video.dao.CommentDao;
import org.balabala.video.dao.ContributeDao;
import org.balabala.video.dao.FavoriteInfoDao;
import org.balabala.video.dao.VideoDao;
import org.balabala.video.entity.Comment;
import org.balabala.video.entity.Contribute;
import org.balabala.video.entity.FavoriteInfo;
import org.balabala.video.entity.VideoEntity;
import org.balabala.video.service.VideoService;
import org.balabala.video.utils.FetchFrame;
import org.balabala.video.utils.IdGenerator;
import org.balabala.video.utils.Resp;
import org.balabala.video.utils.Time;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.*;

@RestController
@RequestMapping("/balabala/video")
public class VideoController {

    @Autowired
    private VideoService videoService;

    @Autowired
    private VideoDao videoDao;

    @Autowired
    private FavoriteInfoDao favoriteInfoDao;

    @Autowired
    private CommentDao commentDao;

    @Autowired
    private ContributeDao contributeDao;

    // ID生成器
    private IdGenerator idGenerator;

    private static final String baseURL = "http://os.jaz.ink/";

    // 对象存储客户端
    private MinIOClient minIOClient;

    {
        try {
            minIOClient = MinIOClientManager.getClient();
            idGenerator = new IdGenerator(6, 5);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @PostMapping(value = "/put_video", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Resp putVideo(@RequestBody MultipartFile file,
                          @RequestParam("video") String videoJson){
        long now = System.currentTimeMillis();
        Contribute contribute = new Contribute();
        VideoEntity video = JSON.parseObject(videoJson, VideoEntity.class);

        try {
            video.setVideoId(idGenerator.generateId());
            video.setVideoUrl(baseURL+video.getVideoId());
            video.setCreateTime(new Date(now));
            video.setPlayNum(0);
            video.setFavoriteNum(0);
            video.setState(0);
            contribute.setContributeId(idGenerator.generateId());
            contribute.setVideoId(video.getVideoId());
            contribute.setUid(video.getUid());
            contribute.setContributeStatus(0);

            //抽帧并上传
            ByteArrayOutputStream frameStream = FetchFrame.fetchFrame(file);
            minIOClient.putObject(video.getVideoId()+"-frame", "image/jpeg", new ByteArrayInputStream(frameStream.toByteArray()));
            //上传视频
            minIOClient.putObject(video.getVideoId().toString(), "video/mp4", file.getInputStream());
            //数据库保存
            videoService.save(video);
            contributeDao.insert(contribute);
            return Resp.ok().setData(video);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
    }

    @PostMapping("/like")
    public Resp like(@RequestParam Long uid, @RequestParam Long videoId) {
        try {
            if (favoriteInfoDao.exist(uid, videoId) == 0) {
                FavoriteInfo info = new FavoriteInfo();
                info.setVideoId(videoId);
                info.setUid(uid);
                info.setFavoriteTime(new Date(System.currentTimeMillis()));
                favoriteInfoDao.insert(info);
            }
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
        return Resp.ok();
    }

    @PostMapping("/unlike")
    public Resp unlike(@RequestParam Long uid, @RequestParam Long videoId) {
        try {
            favoriteInfoDao.deleteByUidAndVideoId(uid, videoId);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
        return Resp.ok();
    }

    @GetMapping("/get_url/{videoId}")
    public Resp getVideoUrl(@PathVariable String videoId) {
        try {
            String url = minIOClient.getObjectUrl(String.valueOf(videoId), Time.hour);
            return Resp.ok().put("url", url);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
    }

    @GetMapping("/get_frame_url/{videoId}")
    public Resp getFrame_url(@PathVariable String videoId) {
        try {
            String url = minIOClient.getObjectUrl(videoId+"-frame", Time.hour);
            return Resp.ok().put("url", url);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
    }

    @PostMapping("/set_play_num")
    public Resp setPlayNum(@RequestParam Long videoId, @RequestParam Integer playNum) {
        try {
            VideoEntity video = videoDao.getByVideoId(videoId);
            if (video.getPlayNum() < playNum) {
                videoDao.updatePlayNum(videoId, playNum);
            }
        } catch (Exception e) {
            Resp.error(e.toString());
        }
        return Resp.ok();
    }

    @PostMapping("/set_play_nums")
    public Resp setPlayNums(@RequestBody Map<Long, Integer> map) {
        try {
            Long videoId;
            Integer playNum;
            for (Map.Entry<Long, Integer> entry : map.entrySet()) {
                videoId = entry.getKey() == null ? 0L : entry.getKey();
                playNum = entry.getValue() == null ? 0 : entry.getValue();
                videoDao.updatePlayNum(videoId, playNum);
            }
            return Resp.ok();
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
    }

    @GetMapping("/info/{videoId}")
    public Resp getVideoInfo(@PathVariable("videoId") Long videoID){
		VideoEntity video = videoDao.getByVideoId(videoID);

        return Resp.ok().setData(video);
    }

    @PostMapping("/save")
    public Resp save(@RequestBody VideoEntity video){
        try {
            videoService.save(video);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
        return Resp.ok();
    }

    @RequestMapping("/update")
    public Resp update(@RequestBody VideoEntity video){
        try {
            videoService.updateById(video);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
        return Resp.ok();
    }

    //下架视频
    @RequestMapping("/off_shelf")
    public Resp offShelf(@RequestBody Long[] videoIds){
		try {
            videoDao.offShelfByVideoId(videoIds);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
        return Resp.ok();
    }

    @PostMapping("/get_videos_info")
    public Resp getVideosInfo(@RequestBody Long[] videoIds){
        try {
            List<VideoEntity> res = videoDao.getByVideoIds(videoIds);
            return Resp.ok().setData(res);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
    }

    @GetMapping("/get_video/top/played")
    public Resp getTopVideo(@RequestParam Integer num) {
        try {
            List<VideoEntity> res = videoDao.getTopPlayedVideo(num);
            return Resp.ok().setData(res);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
    }

    //获取视频评论
    @GetMapping("/get_video_comments")
    public Resp getVideoComments(@RequestParam Long videoId,
                                 @RequestParam Integer limit,
                                 @RequestParam Integer offset) {
        try {
            int count = commentDao.countByVideoId(videoId);
            if (count <= 0) return Resp.ok();
            List<Comment> res = commentDao.getByVideoIdLimitOffset(videoId, limit, offset);
            return Resp.ok().put("count", count).setData(res);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }
    }


    @GetMapping("/get_user_videos")
    public Resp getUserVideos(@RequestParam Long uid,
                              @RequestParam Integer page,
                              @RequestParam Integer limit){

        try {
            List<VideoEntity> videos = videoDao.getVideoByUid(uid,page,limit);
            return Resp.ok().setData(videos);
        } catch (Exception e) {
            return Resp.error(e.toString());
        }

    }

}
